#!/usr/bin/env python
# -*- encoding: utf-8 -*-
'''
@NAME          : ctfileAct.py
@TIME          : 2022/05/22 21:24:08
@AUTHOR        : chenlip
@VERSION       : 0.0.x
@DESCRIPTION   : 城通网盘操作
'''
import os, json, sys, time, shutil, datetime
import requests, urllib3
import uuid

from common.utils import Utils as ut
from conf.config import Config as conf
from common.logutil import log

import lxml.html
from lxml import etree
import xml.etree.ElementTree as ET # 这是XML处理的包
from requests_html import HTMLSession

class ctAct(object):

    ctrest_url = "https://rest.ctfile.com"
    # 请求类型
    headers = {'content-Type': 'application/json'}
    f_headers= {'content-Type': 'multipart/form-data'}

    _rootres = conf.COMROOTRES

    # 功能获取最新的文件信息,并保存数据库
    # 开始----- 变量定义
    actpath = os.path.join(_rootres, 'cache\ctfile', conf.CURYEAR, conf.CURDAY)
    if(not os.path.exists(actpath)): os.mkdir(actpath)
    
    jsonfn_t = "ctfile.json"

    # 分类信息

    ct = {
        'prodid': "18,3,5,9,10,11,12,13,14",
        'devid': "18,3,5,9,10,11,12,13,14",
        'str': "书单推荐,文学小说,生活百科,计算机IT,经济管理,社科人文,教育学习,科学技术,其他",
        'dirstr': "00书单推荐,10文学小说,20生活百科,30计算机IT,40经济管理,50社科人文,60教育学习,70科学技术,80其他",
        'ctfd_id_2022': "48907326,48574938,48574944,48574950,48574932,48574956,48574962,48574968,48907422",
        'ctfd_id_2023': "48907329,48574941,48574947,48574953,48574935,48574959,48574965,48574971,48907425",
        'ctfd_id_2024': "48907332,48907449,48907446,48907443,48907440,48907437,48907431,48907434,48907428",
        'ctfd_id_2025': "59496070,59496112,59496106,59496100,59496094,59496064,59496088,59496082,59496076",
        'ctfd_id_2026': "59496073,59496115,59496109,59496103,59496097,59496067,59496091,59496085,59496079"
    }

    # 结束----- 变量定义


    def __init__(self):
        # 初始化
        # 一年有效期的token
        self._access_key = conf.CTWP['access_key']
        # 临时手机号登录获取用的token
        self._token = conf.CTWP['token']
        # 默认手机号
        self._phone = conf.CTWP['phone']
        # 是否需要验证ssl
        self._sslverify = True
        # 城通公有云的根路径
        self._root_fd_id = conf.CTWP['root_fd_id']
        # 默认下载访问密码
        self._dl_pass = conf.CTWP['dl_pass']


    def ctLoginSMSPhone(self, ph=None):
        ''' 
            通过手机号获取SMS验证码, 先用这个在手机上获取到短信验证码, 然后调用ctLoginSMSPhoneCode 
        '''
        _tup = ()
        if (ph == None): 
            phone = self._phone
        else:
            phone = ph

        ph_lg_url = ctAct.ctrest_url + "/v1/user/auth/login_sms_code"
        ph_data = {"phone" : phone}
        res = requests.post(ph_lg_url, json=ph_data, headers=ctAct.headers, verify=self._sslverify)
        t = json.loads(res.text)
        if(res.status_code==200):
            _tup = (t['vc_timestamp'],t['vc_checksum'])
            log.info(_tup)
        else:
            _tup = (t['code'],t['message'])
            log.info(res.text)
        return _tup
    # ctLoginSMSPhone

    def Accessweblink(self, wlurl):
        ''' 判断Ctfile是否能访问到相关文件的weblink '''
        # https://n802.com/file/12242611-457882340
        # /html/body/main/div/div[1]/div/div/div/div
        # <div class="display-1 text-200 fs-error">404</div>
        # <p class="lead mt-4 text-800 text-sans-serif font-weight-semi-bold">该共享不存在或已失效。</p>
        isaccess = True

        htmsession = HTMLSession()
        htmpage = htmsession.get(wlurl)
        htmpage.html.render(sleep=0.5)
        htmstr = htmpage.html.html
        # print(htmstr)

        parser = etree.HTMLParser(encoding='utf-8')
        htmlobj = etree.HTML(htmstr, parser=parser)
        list_tag = htmlobj.xpath('//div[@class="display-1 text-200 fs-error"]/text()')

        if(list_tag!=None and len(list_tag)>0):
            print(len(list_tag), "404, 该共享不存在或已失效")
            print('err_url:',wlurl)
            isaccess = False
        return isaccess

    def ctLoginByPhone(self, lgdate=None, ph=None):
        if (ph == None): phone = self._phone

        login_url = ctAct.ctrest_url + '/v1/user/auth/login'

        res = requests.post(login_url, json=lgdate, headers=ctAct.headers, verify=self._sslverify)
        t = json.loads(res.text)
        log.info(t)
        
    # ctLoginByPhone

    def getUserProfile(self):
        ''' 
            获取用户基本信息 
            Ref: https://openapi.ctfile.com/docs/ctfile-open-api/ctfile-open-api-1c9k0fl1iktda
        '''
        resturl = ctAct.ctrest_url + '/v1/user/info/profile'
        sess_data = {"session": self._access_key}

        urllib3.disable_warnings(urllib3.exceptions.InsecureRequestWarning)
        res = requests.post(resturl, json=sess_data, headers=ctAct.headers, verify=self._sslverify)
        t = json.loads(res.text)

        print(t)
        return t
    # getuserprofile

    def getFolderList(self, fd_id:str=None, subdir_name:str=None):
        ''' 
            获取文件和文件夹列表,(只返回当前目录的,不返回子目录), 
            https://openapi.ctfile.com/docs/ctfile-open-api/ctfile-open-api-1c9kitkmo2gm8
            :Args:
                - fd_id: 目录id, 默认为根目录
                - subdir_name, 如果这个子文件夹目录不为空, 则获取子文件夹下的所有文件作为列表. 
            :Return:
                返回列表, 元素为字典, 字典包含文件夹和文件的信息 :
                "results":[
                    {
                        "key": "d48574962", # 目录的ID
                        "icon": "folder", # 目录的类型
                        "name": "2022", # 目录的名称
                        "weblink": "https://url76.ctfile.com/d/18566476-48574962-5bce44",
                        "date": 1651654497,
                        "status": 1 # 目录的状态
                    }
                    {
                        "key": "f564013525", # 文件的ID
                        "icon": "file", # 文件的类型
                        "name": "美国语文读本5(2011-1).epub", # 文件的名称
                        "imgsrc": "",   # 文件的缩略图片
                        "weblink": "https://url76.ctfile.com/f/18566476-564013525-eb1352",
                        "size": 1451881,
                        "date": 1649414547,
                        "status": 1
                    }
                ]
        '''
        res_lst = []
        sub_res_lst = []
        resturl = ctAct.ctrest_url + "/v1/public/file/list"
        if(fd_id == None): fd_id = self._root_fd_id

        sess_data = {
            "filter": "null",
            "folder_id": fd_id,
            "orderby": "old",
            "start": "0",
            "session": self._access_key
            }

        urllib3.disable_warnings(urllib3.exceptions.InsecureRequestWarning)
        res = requests.post(resturl, json=sess_data, headers=ctAct.headers, verify=self._sslverify)
        
        if(res.status_code==200):
            t = json.loads(res.text)
            if(t['code']==200):
                res_lst = t['results']

                # 如果指定了子文件夹，则获取子文件夹的文件列表; 
                if(subdir_name!=None):
                    sub_res_lst = self.getFolderList(self.FindSubdirIDFromFatherLST(res_lst,subdir_name), None)

            else:
                log.info(t['message'])

        else:
            log.info(str(res.status_code)+"服务器访问出现问题:\n"+res.text)

        if(subdir_name!=None):
            print(subdir_name, "==共有多少个文件------", len(sub_res_lst))
            return sub_res_lst
        else:
            print(fd_id, "==共有多少个文件------", len(res_lst))
            return res_lst

    # getFolderList

    def FindSubdirIDFromFatherLST(self, fathidlst:list, subname:str):
        '''
            从指定的父文件夹中找到指定子目录的ID
            :Args:
                - fathidlst : 父文件夹的 results list
                - subname : 待查找ID的子文件夹名称
            :Return:
                返回要查找子文件夹的ID
        '''
        _subid = ""
        for x in fathidlst:
            if(subname == str(x["name"])):
                _subid = str(x["key"])[1:]
                break
            
        return _subid

    def getFileShareDLUrl(self, fn_id:str=None):
        ''' 
            获取单个文件分享链接, 
            https://openapi.ctfile.com/docs/ctfile-open-api/ctfile-open-api-1c9m38pqjn58v
            :Args:
                - fd_id: 文件ID
            :Return:
                返回字典, 包含文件的下载链接 :
                {
                    "results": [
                        {
                            "key": "d31688206",
                            "icon": "folder",
                            "name": "视频格式",
                            "weblink": "https://089u.com/dir/10741048-31688206-4bb787", # 接口现在默认生成的share url增加了"（访问密码）"，需要去掉
                            "xtlink": "ctfile://xturlVzYFb1IyBTULaQQ7VjheMlcyUWNWdFUvVGkFblAxVWRUZVA2UTIEMQFtDSxWdFo5WD0",
                            "size": 0,
                            "date": "2018-12-20"
                        },
                        {
                            "key": "f229307016",
                            "icon": "file",
                            "name": "fname.jpg",
                            "weblink": "https://089u.com/file/10741048-229307016", # 接口现在默认生成的share url增加了"（访问密码）"，需要去掉
                            "xtlink": "ctfile://xturlBmUFbwJjBzQGa1JmUjQBaFM2VGFUZg4nB3JbPAVlBzEGNAZlA2ELOgNjV2gBcVx2A2tRZQ",
                            "directlink": "http://10741048.d.cturls.net/down/10741048/fname.jpg",
                            "size": "12.06 GB",
                            "date": "2017-11-22"
                        }
                    ]
                }
        '''
        _max_retries = int(conf.CTWP['net_max_retries']) # 设置最大重试次数
        _net_sleep = int(conf.CTWP['net_sleep']) # 设置重试间隔时间

        f_dl_lst = []
        if (fn_id != None): 
            fid = fn_id
            resturl = ctAct.ctrest_url + '/v1/public/file/share'
            sess_data = {
                "session": self._access_key,
                "ids": [fid]
                }

            urllib3.disable_warnings(urllib3.exceptions.InsecureRequestWarning)
            # 如果发送requests.exceptions.ConnectionError, 则重试下面代码5次
            for i in range(_max_retries):
                try:
                    res = requests.post(resturl, json=sess_data, headers=ctAct.headers, verify=self._sslverify)
                    if(res.status_code==200):
                        t = json.loads(res.text)
                        if(t['code']==200):
                            f_dl_lst = t['results']
                        else:
                            log.info(t['message'])
                    else:
                        log.info(str(res.status_code)+"服务器访问出现问题:\n"+res.text)
                    
                    break

                except requests.exceptions.ConnectionError as e:
                    if i < _max_retries - 1:  # i is zero indexed
                        log.error(e)
                        print("诚通网盘, getFileShareDLUrl, ConnectionError, 重试次数: ", i+1, "次")
                        time.sleep(_net_sleep)  # wait before trying again
                        continue
                    else:
                        raise

        else:
            log.info("file id is None")
        
        # 格式化f_dl_lst列表中的weblink, 使其可以直接访问, 如果 _weblink 中包含字符串 “（访问密码”，则以该字符串分隔成两部分，取第一部分
        for x in f_dl_lst:
            if(x['icon'] == 'file'):
                _weblink = str(x['weblink'])
                if(_weblink.find("（访问密码")>0):
                    _weblink = _weblink.split("（访问密码")[0]
                    x['weblink'] = _weblink.strip()

        if len(f_dl_lst)>0:
            print(ut.cco("诚通网盘生成的共享weblink","green"), f_dl_lst[0]['name'], f_dl_lst[0]['weblink'])
        else:
            print(ut.cco("诚通网盘生成的共享weblink","red"), "没有找到文件")

        return f_dl_lst
    # getFileShareDLUrl

    # 获取分类文件夹的ID
    def getFDIDbyCate(self, cate_name:str="其他"):
        ''' 
            获取分类文件夹的ID
            :Args:
                - cate_name: 分类名称, 例如: 文学小说
            :Return:
                返回带序号的目录名称
        '''
        fdid = ""
        fd_ctkey = "ctfd_id_"+conf.CURYEAR
        fdid_lst = self.ct[fd_ctkey].split(",")
        ctdirlt = self.ct['dirstr'].split(",")
        for x in ctdirlt:
            if (x.find(cate_name)>0):
                i = ctdirlt.index(x)
                fdid = fdid_lst[i]
                break

        return fdid.strip()


    def getUploadURL(self, cate_name:str="其他", f_name:str="c:/abc.epub", fsize:int=0):
        ''' 
            上传文件到CtFile, 其实只用两个参数就OK, 官方的API说明文档有点坑;
            下面这三个参数其实不必要；
            "checksum ": uuidFour,
            "size ": str(fsize),
            "name" : f_n
            另外： 上传链接获取一次后可反复使用24小时
            :Args:
                - cate_name: 分类名称, 例如: 文学小说
                - f_name: 文件名称, 例如: 红楼梦.epub c:/home/ctfile/红楼梦.epub
                - fsize: 文件尺寸大小
            :Return:
                返回上传文件的URL地址和相关参数;
        '''
        _curuploadurl = "" # 下载的URL
        fd_id = self.getFDIDbyCate(cate_name) # 获取分类文件夹的ID, 分类下面的年份指定的目录;

        # 记录下UploadURL
        # os.fspath(_approotpath + "\\conf\\inportconf.json").replace("\\\\","\\")
        # _jsonfn = os.path.join(dy.getYamlValByKey("resrootpath"), "templates\\ctupurl_"+conf.CURYEAR+".json")
        _jsonfn = os.fspath(conf['APPLICATION_ROOT'] + "\\conf\\ctupurl_"+conf.CURYEAR+".json").replace("\\\\","\\")
        # print("**=======**", _jsonfn, cate_name, fd_id)
        # print("文件尺寸(M):", '{:.2f}'.format(fsize/1024/1024), "文件名称:", os.path.basename(f_name))
        _urljson = json.loads(open(_jsonfn, 'r', encoding='utf-8').read())

        if(conf.CURDAY == _urljson[fd_id]["createTime"]): # 已经存在今天的uploadurl
            _curuploadurl = _urljson[fd_id]["uploadurl"]
            print("已经存在今天的uploadurl", _curuploadurl)

        else:
            
            # 判断是否存在今天的目录了， 如果不存在今天的目录则创建之
            _tardirid = self.createCtDIR(cate_name=cate_name, _dirn=conf.CURDAY)

            # 获取新的下载URL, 并记录到JSON下来
            # 预计算特征值 文件的md5+size
            # uuidFour = dy.getFileMD5(f_name) + "-" + str(fsize)

            resturl = ctAct.ctrest_url + "/v1/public/file/upload"
            sess_data = {
                "session": self._access_key,
                "folder_id": _tardirid
                }

            _h = {"content-type": "application/json"}
            
            urllib3.disable_warnings(urllib3.exceptions.InsecureRequestWarning)
            res = requests.post(resturl, headers=_h, json=sess_data, verify=self._sslverify)
            t = json.loads(res.text)
            _curuploadurl = str(t["upload_url"])

            # 写入到json文件中
            _urljson[fd_id]["createTime"] = conf.CURDAY
            _urljson[fd_id]["uploadurl"] = _curuploadurl

            with open(_jsonfn, 'w', encoding='utf-8') as w_f:
                json.dump(_urljson, w_f, indent=4, ensure_ascii=False)
            
            print("不存在今天的uploadurl, 需要重新获取:", _curuploadurl)

        return _curuploadurl
    # getUploadURL

    def uploadCtFile(self, f_name:str, cate_name:str="其他"):
        ''' 执行上传 '''

        # 1- 先获取上传文件的URL
        fsize = os.path.getsize(f_name) # 获取文件大小
        url_t = self.getUploadURL(cate_name, f_name, fsize) # 先获取到上传的URL
        exfn = os.path.basename(f_name)
        _flst = []

        _isok = self.isExiteFromJSON(f_name) # 判断是否已经上传过了, False表示不存在
        if (not _isok):
            # 2- 再上传文件
            f_data = {
                "name": exfn,
                "filesize ": str(fsize)
                }

            files=[('file',(exfn, open(f_name,'rb'),'application/octet-stream'))]
            ctupheaders= {}

            urllib3.disable_warnings(urllib3.exceptions.InsecureRequestWarning)

            _max_retries = int(conf.NET_CONN['net_max_retries']) # 设置最大重试次数
            _net_sleep = int(conf.NET_CONN['net_sleep']) # 设置重试间隔时间
            
            for i in range(_max_retries):
                try:
                    res = requests.request("POST", url_t, headers=ctupheaders, data=f_data, files=files)
                    
                    if (res.status_code==200): # 上传成功

                        _flst = self.getFileShareDLUrl("f"+res.text)
                        # 追加到今天上传的JSON文件中, 方便下一步step05 直接获取查找,并填充到excle的C20列
                        self.UPFN_AppendJSON(_flst)
                        
                        log.info ("城通网盘文件上传 code==" + str(res.status_code) + ";text==" + res.text + "文件名:" + exfn)

                    break
                except requests.exceptions.SSLError as e:
                    if i < _max_retries - 1:  # i is zero indexed
                        log.error(e)
                        print("发生网络错误, SSL Error, 暂停3秒.重试....", i+1, "次")
                        time.sleep(_net_sleep)  # wait before trying again
                        continue
                    else:
                        raise
                except requests.exceptions.ConnectionError as e:
                    if i < _max_retries - 1:
                        log.error(e)
                        print("发生网络错误, Connection Error, 暂停3秒.重试....", i+1, "次")
                        time.sleep(_net_sleep)  # wait before trying again
                        continue
                    else:
                        raise
                except Exception as e:
                    if i < _max_retries - 1:  # i is zero indexed
                        log.error(e)
                        print("诚通网盘上传发生异常, 暂停3秒.重试....", i+1, "次")
                        time.sleep(_net_sleep)  # wait before trying again
                        continue
                    else:
                        raise
        else:
            print("------------------今天已经上传过了", f_name)
            _flst.append("fname")

        return _flst

    # uploadCtFile

    # 判断是否已经上传成功过, fname是否存在json中
    def isExiteFromJSON(self, fname:str):
        _isok = False # 不存在
        fname = os.path.basename(fname).replace(".epub", "")

        _jsonfn = os.path.join(conf.COMROOTRES, "cache","ctfile",conf.CURYEAR,"ctupload_"+conf.CURDAY+".json")

        if (not os.path.exists(_jsonfn)): # 如果JSON文件不存在则生成JSON文件
            print("暂时: 文件不存在", _jsonfn)
            # _urljson = {"results" : []}
            # with open(_jsonfn, 'w', encoding='utf-8') as w_f:
            #     json.dump(_urljson, w_f, indent=4, ensure_ascii=False)
        
        else: # 如果文件已存在, 则读取它
            _urljson = json.loads(open(_jsonfn, 'r', encoding='utf-8').read())

            _jsonlst = _urljson["results"]
            for x in _jsonlst:
                if ((str(x["name"]).find(fname)>=0)):
                    _isok = True
                    break
        
        return _isok

    def UPFN_AppendJSON(self, fnlst:list):
        ''' 上传文件追加到临时的JSON中 '''
        _jsonfn = os.path.join(conf.COMROOTRES, "cache","ctfile",conf.CURYEAR,"ctupload_"+conf.CURDAY+".json")
        
        if (not os.path.exists(_jsonfn)): # 如果JSON文件不存在则生成JSON文件
            _urljson = {"results" : []}
            with open(_jsonfn, 'w', encoding='utf-8') as w_f:
                json.dump(_urljson, w_f, indent=4, ensure_ascii=False)
        
        else: # 如果文件已存在, 则读取它
            _urljson = json.loads(open(_jsonfn, 'r', encoding='utf-8').read())
        
        _jsonlst = _urljson["results"]
        for x in fnlst:
            _jsonlst.append(x)
        
        _urljson["results"] = _jsonlst

        with open(_jsonfn, 'w', encoding='utf-8') as w_f:
            json.dump(_urljson, w_f, indent=4, ensure_ascii=False)

        return _urljson
            
        

    def ISExite_FromALL(self, idslst:list):
        ''' 
            判断在所有的文件目录中的， 文件或文件夹是否存在 
            :Args:
                - idslst : 文件或文件夹ID 的字符串列表
            :Return:
                {"code":200,"results":["f787983138", "d389861"]}
                返回数值, 如果数值>0 表示存在; 否则表示不存在
        '''
        _isexits = 0
        sess_data = {
            "session": self._access_key,
            "ids" : idslst
        }
        # 判断文件夹或文件是否存在的api URL
        resturl = ctAct.ctrest_url + "/v1/public/file/ids_exists"
        _h = {"content-type": "application/json"}
            
        urllib3.disable_warnings(urllib3.exceptions.InsecureRequestWarning)
        res = requests.post(resturl, headers=_h, json=sess_data, verify=self._sslverify)
        if(res.status_code == 200):
            t = json.loads(res.text)
            _isexits = len(list(t["results"]))

        return _isexits
    
    def ISExite_FromDIR(self, faid:str, _fname:str):
        ''' 
            判断在指定的文件目录中的， 文件或文件夹是否存在 
            :Args:
                - _ftype : 文件 还是文件夹; d 标识文件夹; f 标识文件
                - faid : 文件夹ID 
                - _fname : 待查找的指定的文件名或文件夹名称
            :Return:
                返回数值, 如果0 表示不存在; 文件夹ID "d..." ; 文件id "f......"
        '''
        _falst = self.getFolderList(fd_id=faid)
        _isexite = "0"
        for x in _falst:
            if (_fname == str(x["name"])): 
                _isexite = str(x["key"])
                break
        
        return _isexite


    def createCtDIR(self, cate_name:str="其他", _dirn:str=None, fatherdirid:str=None):
        '''
            创建今天的文件夹, 父文件夹是在调用时传入的
            :Args:
                - cate_name : 分类名称
                - _dirn : 要创建的文件夹名称,例如: 2023-08-01
                - fatherdirid: 父文件夹ID;
            :Return:
                返回创建的文件夹的ID; 
        '''
        _fdctid = ""

        if (fatherdirid!=None):
            fd_id = fatherdirid
        else:
            fd_id = self.getFDIDbyCate(cate_name) # 获取分类文件夹的ID, 分类下面的年份指定的目录;
        
        if(_dirn == None) : _dirn = conf.CURDAY

        _isexitsf = self.ISExite_FromDIR(faid=fd_id, _fname=_dirn)

        if(_isexitsf == "0"):
            # 创建文件夹的参数
            # folder_id 是父目录的ID
            sess_data = {
                "session": self._access_key,
                "folder_id" : fd_id,
                "name" : _dirn,
                "description" : _dirn,
                "is_hidden" : 0
                }

            # 创建文件夹api URL
            resturl = ctAct.ctrest_url + "/v1/public/folder/create"
            _h = {"content-type": "application/json"}
                
            urllib3.disable_warnings(urllib3.exceptions.InsecureRequestWarning)
            res = requests.post(resturl, headers=_h, json=sess_data, verify=self._sslverify)
            t = json.loads(res.text)
            _fdctid = str(t["folder_id"]) # 获取创建的文件夹ID
        else:
            _fdctid = _isexitsf

        return _fdctid

    def _ListToDict(self, lst, ldict):
        ''' 将list转换成dict '''
        d = {}
        for i in lst:
            key ="item_" + str(lst.index(i))
            d[key] = i
        return d

    def _deleteFile(self):
        ''' 删除两天前所有的json文件 '''
        _dir = os.path.join(ctAct._rootres, 'cache\ctfile', conf.CURYEAR)
        for root, dirs, files in os.walk(_dir):
            for d in dirs:
                if (d == conf.CURDAY or d == conf.YESTERDAY):
                    pass
                else:
                    _d = os.path.join(root, d)
                    shutil.rmtree(_d)
        pass
    # _deleteFile

    def _getsubdirbycate(self, results:list):
        _subdir = []
        for ixms in results:
            if(ixms['icon']=='folder'):
                _subdir.append(ixms)

        return _subdir
    # _getsubdirbycate

    def _writesubdirjson(self, catename:str, subdir_lst:list):
        ''' 将子目录写入json文件 '''
        fn, fext = os.path.splitext(ctAct.jsonfn_t)

        for x in subdir_lst:
            _fid = x['key']
            _ficon = x['icon']
            _fname = x['name']

            i = subdir_lst.index(x)

            njsonfn = fn + "_" + catename +"_" + _fname + fext
            njsonfn = os.path.join(ctAct.actpath, njsonfn)

            print(catename + "下面的 njsonfn==", njsonfn)
            
            f_dict = {"category":_fname, "fdid":x, "year":conf.CURYEAR, "results":[]}
            f_lst = self.getFolderList(_fid)
            f_dict["results"] = f_lst

            with open(njsonfn, 'w', encoding='utf-8') as w_f:
                json.dump(f_dict, w_f, indent=4, ensure_ascii=False)

        pass
    # _writesubdirjson

    def getAllFileListToJSON(self):
        ''' 
            获取城通网盘上公有云的所有文件信息并保存到JSON中 
            保存目录在 cache/ctfile/<xxxx-xx-xx>
            同时删除掉两天前的json文件
        '''
        dir_lst = self.ct['dirstr'].split(",")
        
        ctdir_id = self.ct["ctfd_id_" + conf.CURYEAR].split(",")
        
        fn, fext = os.path.splitext(ctAct.jsonfn_t)
        
        _m = 0 # 记录文件个数
        for x in dir_lst: # 循环9个主要分类
            njsonfn = fn +"_" + x + fext
            njsonfn = os.path.join(ctAct.actpath, njsonfn)
            print("njsonfn==", njsonfn)

            i = dir_lst.index(x)
            f_dict = {"category":x, "fdid":ctdir_id[i], "year":conf.CURYEAR, "results":[]}
            f_lst = self.getFolderList(ctdir_id[i])
            f_dict["results"] = f_lst

            with open(njsonfn, 'w', encoding='utf-8') as w_f:
                json.dump(f_dict, w_f, indent=4, ensure_ascii=False)
            
            # 获取子目录并写入json文件
            subdir_lst = self._getsubdirbycate(f_lst)
            self._writesubdirjson(x, subdir_lst)

        self._deleteFile() # 删除两天前的json文件
        
    # getAllFileListToJSON

    def getCTFileJsonToDict(self):
        ''' 初始化读取ctfile json文件, 转换为字典, 预计有100K左右 '''
        _rootres = conf.COMROOTRES
        actpath = os.path.join(_rootres, 'cache', 'ctfile', self.curYear, self.curDay)
        dst_lst = self.ct['dirstr'].split(',')
        json_dist = {}

        for dst in dst_lst:
            catestrfn = "ctfile_"+ dst +".json"
            json_dist[dst] = json.load(open(os.path.join(actpath, catestrfn), 'r', encoding='utf-8'))
            
            subdir_lst = self._getsubdirbycate(json_dist[dst]['results']) # 子目录列表

            for sbj in subdir_lst:
                # njsonfn = fn + "_" + catename +"_" + _fname + fext
                # ctfile_10文学小说_2022-07-05.json
                _dkey = sbj['key']
                _dname = sbj['name']
                catesubjson = "ctfile_"+ dst + "_" + _dname +".json"
                json_dist[_dkey] = json.load(open(os.path.join(actpath, catesubjson), 'r', encoding='utf-8'))
                
        return json_dist
    
    def getCtFileInfoFromJSON(self, bkfnname:str, jsondict=None):
        ''' 根据文件名称获取文件信息 '''
        
        '''
            {
                "key": "f229307016",
                "icon": "file",
                "name": "fname.jpg",
                "weblink": "https://089u.com/file/10741048-229307016",
                "xtlink": "ctfile://xturlBmUFbwJjBzQGa1JmUjQBaFM2VGFUZg4nB3JbPAVlBzEGNAZlA2ELOgNjV2gBcVx2A2tRZQ",
                "directlink": "http://10741048.d.cturls.net/down/10741048/fname.jpg",
                "size": "12.06 GB",
                "date": "2017-11-22"
            }
        '''
        if (jsondict == None):
            _jsondict = self.getCTFileJsonToDict()
        else:
            _jsondict = jsondict
            
        dst_lst = self.ct['dirstr'].split(',') # dirstr: "00书单推荐,10文学小说

        refninfo = {}

        for dst in dst_lst:
            json_dist = {}
            json_dist = _jsondict[dst]
            f_lst = json_dist["results"] # 获取数据列表

            for f in f_lst:
                _ficon = f["icon"]
                if(_ficon == 'file'):
                    if ((str(f["name"]).find(bkfnname)>=0)):
                        refninfo = f
                        break
                else:
                    if(_ficon == 'folder'):
                        ''' 获取子文件夹的文件信息, 并到子文件夹中查询 '''
                        _fdkey = f['key']
                        _js_dict = {}
                        _js_dict = _jsondict[_fdkey]
                        _sub_f_lst = _js_dict["results"] # 获取数据列表
                        for m in _sub_f_lst:
                            if ((str(m["name"]).find(bkfnname)>=0) and (m['icon'] == 'file')):
                                refninfo = m
                                break
            
        return refninfo

    def getfnFormUploadJSON(self, bkfnname:str):
        ''' 根据文件名称, 从当天的上传记录中获取文件的weblink 
            :Args: 
                - bkfnname; 文件名称, 并非全路径
        '''
        _jsonfn = os.path.join(conf.COMROOTRES, "cache","ctfile",conf.CURYEAR,"ctupload_"+conf.CURDAY+".json")
        
        if (not os.path.exists(_jsonfn)): # 如果JSON文件不存在则生成JSON文件
            print("错误: 文件不存在", _jsonfn)
        else: # 如果文件已存在, 则读取它
            _urljson = json.loads(open(_jsonfn, 'r', encoding='utf-8').read())
        
        _jsonlst = _urljson["results"]
        refninfo = {}
        for x in _jsonlst:
            if ((str(x["name"]).find(bkfnname)>=0)):
                        refninfo = x
                        break
        # print("refninfo 长度==", len(refninfo), bkfnname)
        return refninfo


